home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / DDJMAG / DDJ9207.ZIP / ACOMP.ZIP / AC.ASM next >
Assembly Source File  |  1992-04-12  |  13KB  |  516 lines

  1. ;; AC.ASM        -> ACOMP assembly language compressor.    Written
  2. ;;               by John W. Ratcliff, 1992.  Uses Turbo Assembler
  3. ;;               IDEAL mode and makes HEAVY use of macros.  This
  4. ;;               algorithm performs an exhaustive search for the
  5. ;;               best delta mod for each section of the waveform.
  6. ;;               It is very CPU intensive, and the algorithm can
  7. ;;               be a little difficult to follow in assembly
  8. ;;               language.
  9. ;;
  10. ;; You could develop a faster version of this algorithm by changing some of
  11. ;; the rules regarding how to find the best matching delta modulation values.
  12. ;; Also, when a RESYNC occurs you might continue to assume resyncing for an
  13. ;; entire frame.  Another optimization would involve changing the allowable
  14. ;; error thershold relative the frequency response of the data at any given
  15. ;; time.  Note that many changes and improvements may be made to the
  16. ;; compression algorithm without causing changes in the ACOMP file format.
  17. ;;
  18. ;; It might be interesting to note that ACOMP is successful at compressing
  19. ;; A/D converted data other than simply digital audio.    Using ACOMP on a
  20. ;; black and white gray scale image achieved better than 4:1 compression with
  21. ;; very little loss of visual detail.
  22.  
  23.  
  24.     IDEAL            ; Enter Turbo Assembler's IDEAL mode.
  25.     JUMPS            ; Allow automatic jump sizing.
  26.     INCLUDE "prologue.mac"  ; Include usefull assembly lanugage macro file.
  27.  
  28. SEGMENT _TEXT    BYTE PUBLIC 'CODE'
  29.     ASSUME    CS:_TEXT
  30.  
  31. ;; This macro computes the amount of error in a frame of data, at this
  32. ;; bit resolution and this delta mod location.
  33. Macro    DoError BITS
  34.     LOCAL    @@NO
  35.     mov    bx,[COMP]        ; Current delta mod value.
  36.     mov    bh,BITS         ; Current bit resolution.
  37.     push    [MINERR]        ; Pass minimum error so far.
  38.     push    [PREV]            ; Pass previous data point.
  39.     call    ComputeError        ; Compute error for frame.
  40.     add    sp,4            ; Balance stack.
  41.     cmp    dx,[MINERR]        ; Less than previous minimum?
  42.     jge    @@NO            ; no, don't update.
  43.     mov    [MINERR],dx        ; Save as new miniume
  44.     mov    [BESTPREV],ax        ; Best previous location.
  45.     xor    ah,ah            ;
  46.     mov    al,bl            ; Get best delta modution.
  47.     mov    [BEST1],ax        ; save it.
  48.     mov    al,bh            ; Get best bits.
  49.     mov    [BEST2],ax        ; Save it.
  50. @@NO:
  51.     endm
  52.  
  53. SQLCH    equ    64        ; Squelch bit.
  54. RESYNC    equ    128        ; Resynchronization bit.
  55.  
  56. DELTAMOD equ    00110000b    ; Bit mask for delta mod bits.
  57.  
  58. ONEBIT    equ    00010000b    ; Bit pattern for one bit delta mod.
  59. TWOBIT    equ    00100000b    ; Bit pattern for two bit delta mod.
  60. FOURBIT equ    00110000b    ; Bit pattern for two bit delta mod.
  61.  
  62. ;; This macro echos a message to the text screen, so that we can
  63. ;; monitor the progress of the compression algorithm.
  64. Macro    Note    MSG
  65.     push    ax
  66.     lea    ax,[MSG]
  67.     push    ax
  68.     call    Notify
  69.     add    sp,2
  70.     pop    ax
  71.     endm
  72.  
  73.  
  74.     public    _CompressAudio
  75. ;; This the the ACOMP compression procedure.
  76. ;;int far CompressAudio(unsigned char far *shand, Address of audio data to compress.
  77. ;;            unsigned char far *dhand, Destination address of compressed data.
  78. ;;            unsigned int slen, Length of audio data to compress.
  79. ;;            int squelch,       Squelch value allowed.
  80. ;;            int freq,       Playback frequency of audio data.
  81. ;;            int frame,       Frame size.
  82. ;;            int maxerr);       Maximum error allowed.
  83. Proc    _CompressAudio    far
  84.     ARG    SHAN:DWORD,DHAN:DWORD,SLEN:WORD,SQUELCH:WORD,FREQ:WORD,FRAME:WORD,MAXERR:WORD
  85.     LOCAL    PREV:WORD,COMP:WORD,MINERR:WORD,BEST1:WORD,BEST2:WORD,BESTPREV:WORD = LocalSpace
  86.     PENTER    LocalSpace
  87.     PushCREGS
  88.  
  89.     lds    si,[SHAN]        ; Get source address.
  90.     les    di,[DHAN]        ; Get destination address.
  91.     mov    cx,[SLEN]        ; Get length of audio data.
  92.  
  93.     mov    ax,cx        ; Get length of audio sample into AX
  94.     stosw            ; Store it.
  95.     mov    ax,[FREQ]    ; Get frequency of recording.
  96.     stosw            ; Store it.
  97.     mov    ax,[FRAME]    ; Get the frame size.
  98.     stosb            ; Store it.
  99.     mov    ax,[SQUELCH]    ; Get squelch size
  100.     stosb            ; Store it.
  101.     mov    ax,[MAXERR]    ; Get maximum error allowed.
  102.     stosw            ; Save it.
  103.     xor    ax,ax
  104.     lodsb            ; Get first data sample
  105.     mov    [PREV],ax
  106.     stosb            ; Store first data sample.
  107.     dec    cx        ; Decrement sample size count.
  108.     jz    @@DONE
  109.  
  110. @@SQU:    mov    ah,0Bh        ; Test keyboard status.
  111.     int    21h
  112.     or    al,al
  113.     jz    @@NOK
  114.     mov    ah,08h        ; If a key was pressed get that key
  115.     int    21h        ; value, and see if it was the
  116.     cmp    al,27        ; escape key.
  117.     jne    @@NOK
  118.     xor    ax,ax        ; If escape, return to caller, with abort.
  119.     jmp    @@EXIT
  120. @@NOK:
  121.     xor    ax,ax
  122.     mov    dx,[SQUELCH]    ; Get squelch value.
  123.     push    cx        ; Save remaining data count.
  124.     push    si        ; Save si.
  125. @@CK1:    lodsb            ; Get data byte.
  126.     sub    ax,[PREV]    ; Difference from previous data sample?
  127.     jns    @@CK2        ; if positive leave it alone.
  128.     neg    ax        ; Make it positive.
  129. @@CK2:    cmp    ax,dx        ; Is it within the squelch range?
  130.     jg    @@NOS        ; yes, keep checking!
  131.     loop    @@CK1        ; Keep going.
  132.     inc    si        ; Plus one, this last one counts.
  133. @@NOS:    pop    ax        ; Get back start SI
  134.     mov    dx,si        ; DX contains current address.
  135.     sub    dx,ax        ; Compute number of squelch bytes encountered.
  136.     dec    dx        ; Less, last non squelch byte.
  137.     cmp    dx,3        ; At least three?
  138.     jle    @@NOSQ        ; no, don't squelch it.
  139. @@SQS:    cmp    dx,63        ; Is it under 63?
  140.     jle    @@SEND
  141.     mov    ax,(63 + SQLCH)  ; Send count.
  142.     sub    dx,63        ; Less the 63 count we just sent.
  143.     stosb            ; Write squelch byte out.
  144.     jmp short @@SQS     ; Continue.
  145. @@SEND: mov    ax,dx        ; Get remaining count.
  146.     or    ax,SQLCH    ; Or squelch bit on.
  147.     stosb            ; Send squelch count out.
  148.     dec    si        ; Back up to last data point.
  149.     pop    ax        ; Pull CX off of stack, use current count.
  150.     Note    msg0
  151.     jmp short @@NXT
  152. @@NOSQ: mov    si,ax        ; Replace where source was.
  153.     pop    cx        ; Get back remaining data count.
  154.  
  155. @@NXT:    jcxz    @@DONE        ; Exit if done.
  156.     cmp    cx,[FRAME]    ; Below current frame size?
  157.     jae    @@GO        ; no, go ahead.
  158. @@FIN:    lodsb            ; Get raw sample.
  159.     shr    al,1        ; Down to closest aproximated value.
  160.     or    al,RESYNC    ; Add resync bit to it.
  161.     stosb            ; Store out.
  162.     loop    @@FIN        ; Keep sending final bytes.
  163.     jmp    @@DONE        ; exit, after sending final bytes.
  164.  
  165. @@GO:    mov    [MINERR],07FFFh
  166.     push    cx
  167.     mov    cx,[FRAME]    ; Set CX to frame size.
  168.  
  169.     mov    [COMP],1
  170. @@ALL1: DoError 1        ; Try one bit mode, +/-1.
  171.     inc    [COMP]
  172.     cmp    [COMP],17    ; Try delta comp values clean up to 16!!
  173.     jne    @@ALL1
  174.  
  175.     mov    ax,[MINERR]
  176.     cmp    ax,[MAXERR]
  177.     jle    @@BCMP        ; Not good enough...
  178.     mov    [COMP],1
  179. @@ALL2: DoError 2        ; Try two bit mode, +/-1.
  180.     inc    [COMP]
  181.     cmp    [COMP],17    ; Try delta comp values clean up to 16!!
  182.     jne    @@ALL2
  183.  
  184.     mov    ax,[MINERR]
  185.     cmp    ax,[MAXERR]
  186.     jle    @@BCMP
  187.     mov    [COMP],1
  188. @@ALL4: DoError 8        ; Try four bit mode, +/-1.
  189.     inc    [COMP]
  190.     cmp    [COMP],17    ; Try delta comp values clean up to 16!!
  191.     jne    @@ALL4
  192.  
  193.     mov    ax,[MINERR]    ; Get what the minimum error was.
  194.     cmp    ax,[MAXERR]    ; Minimum error > maximum error?
  195.     jle    @@BCMP        ; no, then send frame.
  196.     pop    cx        ; Get back CX
  197.     lodsb            ; Get data sample.
  198.     and    al,(NOT 1)    ; Strip off bottom bit.
  199.     xor    ah,ah
  200.     mov    [PREV],ax    ; New previous.
  201.     shr    al,1        ; /2
  202.     or    al,RESYNC    ; Or resync bit on.
  203.     stosb            ; Store it out into data stream.
  204.     Note    msg1
  205.     loop    @@SQU        ; Go check squelching.
  206.     jmp    @@DONE        ; Done, if this was last data sample.
  207. @@BCMP: mov    bx,[BEST1]    ; Get best comp.
  208.     mov    ax,[BEST2]    ; Get best bit size.
  209.     mov    bh,al        ; Into BH
  210.     mov    ax,32000
  211.     push    ax
  212.     push    [PREV]        ; Pass prev.
  213.     call    ComputeError    ; Re-compute error term.
  214.     add    sp,4
  215.     mov    [PREV],ax    ; New previous.
  216. ;; Now time to store results!
  217.     mov    bx,[BEST1]    ; Get best comp.
  218.     cmp    [BEST2],1    ; 1 bit?
  219.     jne    @@NXT1
  220.     call    Fold1Bit    ; Fold 1 bit data.
  221.     Note    msg2
  222.     jmp short @@IN        ; Reenter.
  223. @@NXT1: cmp    [BEST2],2    ; 2 bit data?
  224.     jne    @@NXT2
  225.     call    Fold2Bit
  226.     Note    msg3
  227.     jmp short @@IN
  228. @@NXT2:
  229.     call    Fold4Bit
  230.     Note    msg4
  231. @@IN:    mov    ax,[FRAME]
  232.     pop    cx        ; Get back CX
  233.     add    si,ax        ; Advance source
  234.     sub    cx,ax        ; Decrement data count.
  235.     jnz    @@SQU        ; Continue, if not at end.
  236.  
  237. @@DONE:
  238.     mov    ax,di        ; Size of compressed file.
  239.     les    di,[DHAN]
  240.     sub    ax,di        ; Difference.
  241.  
  242. @@EXIT:
  243.     PopCREGS
  244.     PLEAVE
  245.     ret
  246.     endp
  247.  
  248.  
  249. ;; Compute error:
  250. ;;         Registers on entry are:
  251. ;;         DS:SI -> source data.
  252. ;;         CX    -> number of bytes to compute error term in.
  253. ;;         DX    -> total error incurred.
  254. ;;         BL    -> delta comp size.
  255. ;;         BH    -> maximum bit size value, positive or negative.
  256. ;; Exit: CX,DS:SI stay the same.
  257. ;;     DX -> total error term.
  258. ;;     AX -> new previous.
  259. Proc    ComputeError    near
  260.     ARG    PREV:WORD,MINERR:WORD
  261.     LOCAL    CUR:WORD = LocalSpace
  262.     PENTER    LocalSpace
  263.  
  264.     push    cx
  265.     push    si
  266.     push    di        ; Save destination address.
  267.     xor    dx,dx        ; Initally no error.
  268.  
  269. @@CERR: lodsb            ; Get a data byte.
  270.     xor    ah,ah        ; Zero high byte.
  271.     mov    [CUR],ax    ; Save as current sample.
  272.     sub    ax,[PREV]
  273.     cmp    bl,1
  274.     je    @@ND
  275.     idiv    bl        ; Divided by delta mod size.
  276. @@ND:    or    al,al
  277.     js    @@DON        ; Do negative side.
  278.     jnz    @@CNT        ; If not zero then continue.
  279.     inc    al        ; Can't represent a zero, make it one.
  280. @@CNT:    cmp    al,bh        ; > max representative size?
  281.     jle    @@OK        ; no, it fit as is.
  282.     mov    al,bh        ; Make it the max representative size.
  283.     jmp short @@OK        ;
  284. @@DON:    neg    al        ; Make it positive.
  285.     cmp    al,bh        ; > max representative size?
  286.     jbe    @@K2        ; no, use it.
  287.     mov    al,bh        ; Make it the max representative size.
  288. @@K2:    neg    al        ; Make it negative again.
  289. @@OK:
  290.     stosb            ; Store data value out.
  291.     imul    bl        ; Times delta comp value.
  292.     add    ax,[PREV]    ; Add to previous data point.
  293.     js    @@CS        ; Do signed case.
  294.     cmp    ax,255        ; Did it over flow?
  295.     jle    @@K3        ; No, then it fit byte sized.
  296.     mov    ax,255        ; Make it byte sized.
  297.     jmp short @@K3        ; Re-enter
  298. @@CS:    xor    ax,ax        ; Close as we can get, underflow.
  299. @@K3:    mov    [PREV],ax    ; This is our new aproximated value.
  300.     sub    ax,[CUR]    ; Less actual value.
  301.     jns    @@K4        ; if positive then fine.
  302.     neg    ax        ; Take absolute value.
  303. @@K4:    add    dx,ax        ; Add into total error.
  304.     cmp    dx,[MINERR]    ; Greater than minimum error allowed?
  305.     jg    @@OUT
  306.     loop    @@CERR
  307.  
  308. @@OUT:    mov    ax,[PREV]    ; Current previous data point.
  309.     pop    di        ; Restore destination address.
  310.     pop    si        ; Reset SI back to start.
  311.     pop    cx        ; Reset CX back to start.
  312.     PLEAVE
  313.     ret
  314.     endp
  315.  
  316. Macro    BuildByte
  317.     LOCAL    @@HOP1,@@HOP2
  318.     lodsb
  319.     or    al,al        ; Is it signed?
  320.     jns    @@HOP1
  321.     shl    ah,1        ; Rotate.
  322.     jmp short @@HOP2
  323. @@HOP1: stc
  324.     rcl    ah,1
  325. @@HOP2:
  326.     endm
  327.  
  328.  
  329. ;; Fold 1 bit data.
  330. ;; ES:DI -> points to data ready to fold out.
  331. ;; CX-> frame size.
  332. ;; BL-> contains delta size.
  333. Proc    Fold1Bit    near
  334.     push    ds
  335.     push    si
  336.     push    di        ; Header byte address.
  337.     push    es
  338.     pop    ds        ; DS=ES
  339.     mov    si,di        ; Source and dest.
  340.     inc    di        ; skip past header byte.
  341. @@FOLD: xor    ah,ah        ; Dest byte to be built, zero it.
  342.     BuildByte
  343.     BuildByte
  344.     BuildByte
  345.     BuildByte
  346.     BuildByte
  347.     BuildByte
  348.     BuildByte
  349.     BuildByte
  350.     mov    al,ah
  351.     stosb            ; Store it out.
  352.     sub    cx,8        ; Less the 8 samples just folded up.
  353.     jnz    @@FOLD        ; Continue.
  354.  
  355.     pop    si        ; Get back header byte address.
  356.     mov    al,bl        ; Get delta comp size.
  357.     dec    al        ; Less one.
  358.     or    al,ONEBIT    ; Or the One Bit mode flag on.
  359.     mov    [ds:si],al    ; Store header byte.
  360.  
  361.     pop    si
  362.     pop    ds
  363.     ret
  364.     endp
  365.  
  366. ;; 2 Bit Format:  00 -> -2
  367. ;;          01 -> -1
  368. ;;          10 -> +1
  369. ;;          11 -> +2
  370. Macro    BByte
  371.     LOCAL    @@HOP1,@@HOP2
  372.     lodsb
  373.     or    al,al        ; Is it signed?
  374.     jns    @@HOP1
  375.     add    al,2        ; Adjust it.
  376.     jmp short @@HOP2
  377. @@HOP1: inc    al        ; Plus 1 to fit into format size.
  378. @@HOP2: shl    ah,1
  379.     shl    ah,1
  380.     or    ah,al        ; Place bits into byte being built.
  381.     endm
  382.  
  383.  
  384. ;; Fold 2 bit data.
  385. ;; ES:DI -> points to data ready to fold out.
  386. ;; CX-> frame size.
  387. ;; BL-> contains delta size.
  388. Proc    Fold2Bit    near
  389.     push    ds
  390.     push    si
  391.  
  392. @@F2:
  393.  
  394.     push    di        ; Header byte address.
  395.  
  396.     push    es
  397.     pop    ds        ; DS=ES
  398.     mov    si,di        ; Source and dest.
  399.     inc    di        ; skip past header byte.
  400. @@FOLD: xor    ah,ah        ; Dest byte to be built, zero it.
  401.     BByte
  402.     BByte
  403.     BByte
  404.     BByte
  405.     mov    al,ah
  406.     stosb            ; Store it out.
  407.     sub    cx,4        ; Folded up 4 samples.
  408.     jnz    @@FOLD        ; Continue.
  409.  
  410.     pop    si        ; Get back header byte address.
  411.     mov    al,bl        ; Get delta comp size.
  412.     dec    al        ; Less one.
  413.     or    al,TWOBIT    ; Or the One Bit mode flag on.
  414.     mov    [ds:si],al    ; Store header byte.
  415.  
  416.     pop    si
  417.     pop    ds
  418.     ret
  419.     endp
  420.  
  421.  
  422. ;; Four bit format:
  423. ;; 0 -> -8
  424. ;; 1 -> -7
  425. ;; 2 -> -6
  426. ;; 3 -> -5
  427. ;; 4 -> -4
  428. ;; 5 -> -3
  429. ;; 6 -> -2
  430. ;; 7 -> -1
  431. ;; 8 -> +1
  432. ;; 9 -> +2
  433. ;;10 -> +3
  434. ;;11 -> +4
  435. ;;12 -> +5
  436. ;;13 -> +6
  437. ;;14 -> +7
  438. ;;15 -> +8
  439. Macro    Adjust4bit
  440.     LOCAL    @@HOP1,@@HOP2
  441.     lodsb
  442.     or    al,al
  443.     jns    @@HOP1
  444.     add    al,8        ; Adjust it.
  445.     jmp short @@HOP2
  446. @@HOP1: add    al,7        ; Adjust it.
  447. @@HOP2:
  448.     endm
  449.  
  450.  
  451. ;; Fold 4 bit data.
  452. ;; ES:DI -> points to data ready to fold out.
  453. ;; CX-> frame size.
  454. ;; BL-> contains delta size.
  455. Proc    Fold4Bit    near
  456.     push    ds
  457.     push    si
  458.  
  459.     push    di        ; Header byte address.
  460.  
  461.     push    es
  462.     pop    ds        ; DS=ES
  463.     mov    si,di        ; Source and dest the same.
  464.     inc    di        ; skip past header byte.
  465. @@FOLD: Adjust4bit        ; Get first sample.
  466.     ShiftL    al,4        ; Into high nibble.
  467.     mov    ah,al        ; Into AH
  468.     Adjust4bit        ; Get next nibble.
  469.     or    al,ah        ; One whole byte.
  470.     stosb            ; Store it out.
  471.     sub    cx,2        ; Folded up 4 samples.
  472.     jnz    @@FOLD        ; Continue.
  473.  
  474.     pop    si        ; Get back header byte address.
  475.     mov    al,bl        ; Get delta comp size.
  476.     dec    al        ; Less one.
  477.     or    al,FOURBIT    ; Or the One Bit mode flag on.
  478.     mov    [ds:si],al    ; Store header byte.
  479.  
  480.     pop    si
  481.     pop    ds
  482.     ret
  483.     endp
  484.  
  485. msg0    db    "SQUELCH"
  486. msg1    db    "RESYNC "
  487. msg2    db    "1 BIT  "
  488. msg3    db    "2 BIT  "
  489. msg4    db    "4 BIT  "
  490.  
  491. Proc    Notify    near
  492.     ARG    MSG:WORD
  493.     PENTER    0
  494.     PushAll
  495.  
  496.     push    cs
  497.     pop    ds
  498.     mov    ax,0B800h
  499.     mov    es,ax
  500.     mov    si,[MSG]
  501.     xor    di,di
  502.     mov    ah,1Fh
  503.     mov    cx,7
  504. @@SND:    lodsb
  505.     stosw
  506.     loop    @@SND
  507.  
  508.  
  509.     PopAll
  510.     PLEAVE
  511.     ret
  512.     endp
  513.  
  514.     ENDS
  515.     END
  516.